package com.sqlcheck.service.impl;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.*;
import com.sqlcheck.model.SqlStatement;
import com.sqlcheck.service.JavaAnnotationAnalysisService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Stream;

@Slf4j
@Service
@RequiredArgsConstructor
public class JavaAnnotationAnalysisServiceImpl implements JavaAnnotationAnalysisService {

    // 新增依赖注入
    private final MybatisSqlContentProcessor sqlContentProcessor;

    // MyBatis注解
    private static final Set<String> MYBATIS_SQL_ANNOTATIONS = Set.of(
            "Select", "Insert", "Update", "Delete");

    // JPA注解
    private static final Set<String> JPA_SQL_ANNOTATIONS = Set.of(
            "Query", "NamedQuery", "NamedQueries", "NativeQuery");

    // 所有SQL相关注解
    private static final Set<String> ALL_SQL_ANNOTATIONS = new HashSet<>();
    static {
        ALL_SQL_ANNOTATIONS.addAll(MYBATIS_SQL_ANNOTATIONS);
        ALL_SQL_ANNOTATIONS.addAll(JPA_SQL_ANNOTATIONS);
    }

    // MyBatis Mapper标识
    private static final Set<String> MYBATIS_MAPPER_ANNOTATIONS = Set.of(
            "Mapper", "Repository");

    @Override
    public List<SqlStatement> analyzeJavaFile(Path javaFilePath) {
        List<SqlStatement> sqlStatements = new ArrayList<>();

        try {
            if (!Files.exists(javaFilePath)) {
                log.warn("Java文件不存在: {}", javaFilePath);
                return sqlStatements;
            }

            if (!hasOrmAnnotations(javaFilePath)) {
                log.debug("跳过无ORM注解的Java文件: {}", javaFilePath);
                return sqlStatements;
            }

            log.info("开始分析Java文件: {}", javaFilePath);

            JavaParser javaParser = new JavaParser();
            CompilationUnit cu = javaParser.parse(javaFilePath).getResult().orElse(null);

            if (cu == null) {
                log.warn("无法解析Java文件: {}", javaFilePath);
                return sqlStatements;
            }

            // 分析类和接口
            cu.findAll(ClassOrInterfaceDeclaration.class).forEach(classDecl -> {
                if (isMybatisMapper(classDecl) || isJpaRepository(classDecl)) {
                    sqlStatements.addAll(analyzeClass(classDecl, javaFilePath));
                }
            });

            log.info("Java文件分析完成，提取到 {} 条SQL语句: {}", sqlStatements.size(), javaFilePath);

        } catch (IOException e) {
            log.error("读取Java文件失败: " + javaFilePath, e);
        }

        return sqlStatements;
    }

    @Override
    public List<SqlStatement> analyzeJavaDirectory(Path directoryPath) {
        List<SqlStatement> allSqlStatements = new ArrayList<>();

        try {
            if (!Files.exists(directoryPath) || !Files.isDirectory(directoryPath)) {
                log.warn("目录不存在或不是目录: {}", directoryPath);
                return allSqlStatements;
            }

            log.info("开始分析目录下的Java文件: {}", directoryPath);

            try (Stream<Path> paths = Files.walk(directoryPath)) {
                paths.filter(Files::isRegularFile)
                        .filter(path -> path.toString().toLowerCase().endsWith(".java"))
                        .forEach(javaPath -> {
                            List<SqlStatement> statements = analyzeJavaFile(javaPath);
                            allSqlStatements.addAll(statements);
                        });
            }

            log.info("目录分析完成，共提取到 {} 条SQL语句", allSqlStatements.size());

        } catch (IOException e) {
            log.error("遍历目录失败: " + directoryPath, e);
        }

        return allSqlStatements;
    }

    @Override
    public boolean hasOrmAnnotations(Path javaFilePath) {
        try {
            if (!Files.exists(javaFilePath) || !javaFilePath.toString().toLowerCase().endsWith(".java")) {
                return false;
            }

            // 快速检查文件内容是否包含ORM相关注解
            List<String> lines = Files.readAllLines(javaFilePath);
            String content = String.join("\n", lines);

            // 检查是否包含相关注解
            for (String annotation : ALL_SQL_ANNOTATIONS) {
                if (content.contains("@" + annotation)) {
                    return true;
                }
            }

            for (String annotation : MYBATIS_MAPPER_ANNOTATIONS) {
                if (content.contains("@" + annotation)) {
                    return true;
                }
            }

            // 检查JPA相关内容
            return content.contains("@Entity") ||
                    content.contains("@Repository") ||
                    content.contains("JpaRepository") ||
                    content.contains("CrudRepository");

        } catch (IOException e) {
            log.debug("检查文件失败: " + javaFilePath, e);
            return false;
        }
    }

    private List<SqlStatement> analyzeClass(ClassOrInterfaceDeclaration classDecl, Path sourceFile) {
        List<SqlStatement> sqlStatements = new ArrayList<>();

        // 分析方法上的注解
        classDecl.getMethods().forEach(method -> {
            sqlStatements.addAll(analyzeMethod(method, sourceFile, classDecl.getNameAsString()));
        });

        return sqlStatements;
    }

    private List<SqlStatement> analyzeMethod(MethodDeclaration method, Path sourceFile, String className) {
        List<SqlStatement> sqlStatements = new ArrayList<>();

        method.getAnnotations().forEach(annotation -> {
            SqlStatement statement = extractSqlFromAnnotation(annotation, method, sourceFile, className);
            if (statement != null) {
                sqlStatements.add(statement);
            }
        });

        return sqlStatements;
    }

    private SqlStatement extractSqlFromAnnotation(AnnotationExpr annotation, MethodDeclaration method,
            Path sourceFile, String className) {
        String annotationName = annotation.getNameAsString();

        if (!ALL_SQL_ANNOTATIONS.contains(annotationName)) {
            return null;
        }

        String sqlContent = extractSqlFromAnnotationExpr(annotation);
        if (sqlContent == null || sqlContent.trim().isEmpty()) {
            return null;
        }

        return SqlStatement.builder()
                .content(cleanSqlContent(sqlContent))
                .sourceFile(sourceFile.toString())
                .sourceType(determinateSourceType(annotationName))
                .sqlType(determineSqlTypeFromAnnotation(annotationName))
                .lineNumber(annotation.getBegin().map(pos -> pos.line).orElse(null))
                .columnNumber(annotation.getBegin().map(pos -> pos.column).orElse(null))
                .className(className)
                .methodName(method.getNameAsString())
                .isNativeQuery(isNativeQuery(annotation))
                .build();
    }

    /**
     * 增强版SQL提取方法，支持复杂字符串拼接表达式
     */
    private String extractSqlFromAnnotationExpr(AnnotationExpr annotation) {
        if (annotation instanceof SingleMemberAnnotationExpr) {
            SingleMemberAnnotationExpr singleMember = (SingleMemberAnnotationExpr) annotation;
            return extractStringFromExpression(singleMember.getMemberValue());
        } else if (annotation instanceof NormalAnnotationExpr) {
            NormalAnnotationExpr normalAnnotation = (NormalAnnotationExpr) annotation;
            for (MemberValuePair pair : normalAnnotation.getPairs()) {
                String name = pair.getNameAsString();
                if ("value".equals(name) || "query".equals(name)) {
                    return extractStringFromExpression(pair.getValue());
                }
            }
        }
        return null;
    }

    /**
     * 增强版字符串表达式提取，支持复杂拼接和方法调用
     */
    private String extractStringFromExpression(Expression expr) {
        if (expr instanceof StringLiteralExpr) {
            // 简单字符串字面量
            return ((StringLiteralExpr) expr).asString();
        } else if (expr instanceof BinaryExpr) {
            // 字符串拼接表达式
            return extractFromBinaryExpression((BinaryExpr) expr);
        } else if (expr instanceof EnclosedExpr) {
            // 括号包围的表达式
            return extractStringFromExpression(((EnclosedExpr) expr).getInner());
        } else if (expr instanceof MethodCallExpr) {
            // 处理字符串方法调用，如 String.format()
            return extractFromMethodCall((MethodCallExpr) expr);
        }
        return null;
    }

    /**
     * 递归处理复杂的二元表达式拼接
     */
    private String extractFromBinaryExpression(BinaryExpr binaryExpr) {
        if (binaryExpr.getOperator() != BinaryExpr.Operator.PLUS) {
            return null;
        }
        
        StringBuilder result = new StringBuilder();
        collectAllStringParts(binaryExpr, result);
        return result.toString();
    }


    /**
     * 递归收集所有字符串片段
     */
    private void collectAllStringParts(Expression expr, StringBuilder collector) {
        if (expr instanceof StringLiteralExpr) {
            collector.append(((StringLiteralExpr) expr).asString());
        } else if (expr instanceof BinaryExpr) {
            BinaryExpr binary = (BinaryExpr) expr;
            if (binary.getOperator() == BinaryExpr.Operator.PLUS) {
                collectAllStringParts(binary.getLeft(), collector);
                collectAllStringParts(binary.getRight(), collector);
            }
        } else if (expr instanceof EnclosedExpr) {
            collectAllStringParts(((EnclosedExpr) expr).getInner(), collector);
        }
        // 对于无法解析的表达式，跳过但不中断整个拼接过程
    }

    /**
     * 处理字符串方法调用
     */
    private String extractFromMethodCall(MethodCallExpr methodCall) {
        // 对于复杂的方法调用，尝试提取参数中的字符串
        String methodName = methodCall.getNameAsString();
        if ("format".equals(methodName) || "valueOf".equals(methodName)) {
            // 尝试从方法参数中提取字符串
            for (Expression arg : methodCall.getArguments()) {
                String extracted = extractStringFromExpression(arg);
                if (extracted != null) {
                    return extracted;
                }
            }
        }
        return null;
    }

    /**
     * 更新cleanSqlContent方法，集成新的处理器
     */
    private String cleanSqlContent(String sqlContent) {
        if (sqlContent == null) {
            return null;
        }
        
        // 使用通用处理器
        if (sqlContentProcessor.needsComplexProcessing(sqlContent)) {
            return sqlContentProcessor.processComplexSql(sqlContent, "ANNOTATION");
        }
        
        // 简单SQL的基础清理
        return sqlContent.replaceAll("\\s+", " ").trim();
    }

    private SqlStatement.SourceType determinateSourceType(String annotationName) {
        if (MYBATIS_SQL_ANNOTATIONS.contains(annotationName)) {
            return SqlStatement.SourceType.MYBATIS_ANNOTATION;
        } else if (JPA_SQL_ANNOTATIONS.contains(annotationName)) {
            return SqlStatement.SourceType.JPA_ANNOTATION;
        }
        return SqlStatement.SourceType.MYBATIS_ANNOTATION; // 默认
    }

    private SqlStatement.SqlType determineSqlTypeFromAnnotation(String annotationName) {
        switch (annotationName.toLowerCase()) {
            case "select":
            case "query":
                return SqlStatement.SqlType.QUERY;
            case "insert":
                return SqlStatement.SqlType.DML;
            case "update":
                return SqlStatement.SqlType.DML;
            case "delete":
                return SqlStatement.SqlType.DML;
            default:
                return SqlStatement.SqlType.QUERY;
        }
    }

    private boolean isNativeQuery(AnnotationExpr annotation) {
        if (annotation instanceof NormalAnnotationExpr) {
            NormalAnnotationExpr normalAnnotation = (NormalAnnotationExpr) annotation;
            for (MemberValuePair pair : normalAnnotation.getPairs()) {
                if ("nativeQuery".equals(pair.getNameAsString())) {
                    return "true".equals(pair.getValue().toString());
                }
            }
        }
        return false;
    }

    private boolean isMybatisMapper(ClassOrInterfaceDeclaration classDecl) {
        return classDecl.getAnnotations().stream()
                .anyMatch(annotation -> MYBATIS_MAPPER_ANNOTATIONS.contains(annotation.getNameAsString()));
    }

    private boolean isJpaRepository(ClassOrInterfaceDeclaration classDecl) {
        // 检查是否继承JPA Repository接口
        return classDecl.getExtendedTypes().stream()
                .anyMatch(type -> {
                    String typeName = type.getNameAsString();
                    return typeName.contains("Repository") ||
                            typeName.contains("CrudRepository") ||
                            typeName.contains("JpaRepository");
                }) ||
                classDecl.getAnnotations().stream()
                        .anyMatch(annotation -> "Repository".equals(annotation.getNameAsString()));
    }
}